/**
 * Copyright (C) 2010 Cloudfarming <info@cloudfarming.nl>
 *
 * Licensed under the Eclipse Public License - v 1.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.eclipse.org/legal/epl-v10.html
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package nl.cloudfarming.client.messaging;

import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.Serializable;
import java.util.Date;
import javax.imageio.ImageIO;
import javax.persistence.Basic;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Lob;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.Transient;
import javax.swing.ImageIcon;
import nl.cloudfarming.client.model.Bean;
import nl.cloudfarming.client.model.Persistable;
import org.openide.util.Exceptions;

/**
 * Represents an incoming message which can be displayed as a notification or in the inbox or in a popup (displaying the content of the message)
 * @author Gerben Feenstra
 */
@NamedQueries(value = {
    @NamedQuery(name = Message.Q_FIND_ALL_MESSAGES, query = "select m from Message m")
})
@Entity
@Table(name = "MESSAGE")
public class Message extends Bean implements Persistable, Serializable {
    
    public static final String Q_FIND_ALL_MESSAGES = "findAllMessages";
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "ID")
    private long id;
    @Column(name = "ORIGIN")
    private String origin;
    @Column(name = "TITLE")
    private String title;
    @Column(name = "MESSAGETEXT", length = 10000)
    private String messageText;
    @Temporal(TemporalType.TIMESTAMP)
    @Column(name = "DATE_RECEIVED")
    private Date dateReceived;
    @Column(name = "IS_READ")
    private boolean read;
    @Transient
    private boolean transientMessage;
    @Transient
    private Image image;
    @Basic(fetch = FetchType.LAZY)
    @Lob
    protected byte[] imageData;
    
    @Transient
    private ImageIcon imageIcon;
    
    public long getId() {
        return id;
    }
    
    public Date getDateReceived() {
        return dateReceived;
    }

    /**
     * sets the date the message is received
     * @param dateReceived the date the message is received
     */
    public void setDateReceived(Date dateReceived) {
        this.dateReceived = dateReceived;
    }
    
    public String getOrigin() {
        return origin;
    }

    /**
     * sets the origin or From of the message
     * @param origin the message origin
     */
    public void setOrigin(String origin) {
        this.origin = origin;
    }

    /**
     * Returns if the message is read
     * @return boolean read
     */
    public boolean isRead() {
        return read;
    }

    /**
     * sets if the message is read
     * @param read 
     */
    public void setRead(boolean read) {
        this.read = read;
    }

    /**
     * gets the text of the message
     * @return the message text
     */
    public String getMessageText() {
        return messageText;
    }

    /**
     * Set the text of the message
     * @param messageText the text to set
     */
    public void setMessageText(String messageText) {
        this.messageText = messageText;
    }
    
    public String getTitle() {
        return title;
    }
    
    public Image getImage() {
        return image;
    }
    
    protected void setImageData(byte[] imageData) {
        this.imageData = imageData;
        ByteArrayInputStream bais = new ByteArrayInputStream(imageData);
        try {
            image = ImageIO.read(bais);
        } catch (IOException ex) {
            Exceptions.printStackTrace(ex);
        }
        imageIcon = new ImageIcon(image);
    }
    
    public void setImage(Image image) {
        assert image != null;
        this.image = image;
        try {
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            
            BufferedImage bi = new BufferedImage(
                    image.getWidth(null),
                    image.getHeight(null),
                    BufferedImage.TYPE_INT_RGB);
            
            Graphics2D g2 = bi.createGraphics();
            g2.drawImage(image, 0, 0, null);
            ImageIO.write(bi, "png", bos);            
            imageData = bos.toByteArray();
        } catch (IOException ex) {
            Exceptions.printStackTrace(ex);
        }
        imageIcon = new ImageIcon(image);
    }
    
    public boolean isTransientMessage() {
        return transientMessage;
    }
    
    public void setTransientMessage(boolean transientMessage) {
        this.transientMessage = transientMessage;
    }
    
    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final Message other = (Message) obj;
        if (this.id != other.id) {
            return false;
        }
        if ((this.origin == null) ? (other.origin != null) : !this.origin.equals(other.origin)) {
            return false;
        }
        if ((this.title == null) ? (other.title != null) : !this.title.equals(other.title)) {
            return false;
        }
        if ((this.messageText == null) ? (other.messageText != null) : !this.messageText.equals(other.messageText)) {
            return false;
        }
        if (this.dateReceived != other.dateReceived && (this.dateReceived == null || !this.dateReceived.equals(other.dateReceived))) {
            return false;
        }
        if (this.read != other.read) {
            return false;
        }
        if (this.transientMessage != other.transientMessage) {
            return false;
        }
        if (this.image != other.image && (this.image == null || !this.image.equals(other.image))) {
            return false;
        }
        return true;
    }
    
    @Override
    public int hashCode() {
        int hash = 7;
        hash = 37 * hash + (int) (this.id ^ (this.id >>> 32));
        hash = 37 * hash + (this.origin != null ? this.origin.hashCode() : 0);
        hash = 37 * hash + (this.title != null ? this.title.hashCode() : 0);
        hash = 37 * hash + (this.messageText != null ? this.messageText.hashCode() : 0);
        hash = 37 * hash + (this.dateReceived != null ? this.dateReceived.hashCode() : 0);
        hash = 37 * hash + (this.read ? 1 : 0);
        hash = 37 * hash + (this.transientMessage ? 1 : 0);
        hash = 37 * hash + (this.image != null ? this.image.hashCode() : 0);
        return hash;
    }

    public ImageIcon getImageIcon() {
        return imageIcon;
    }

    
    /**
     * set the title of the message
     * @param title the message title
     */
    public void setTitle(String title) {
        this.title = title;
        
        
    }
    
    public static class Builder {
        
        private Message message;
        
        public Builder() {
            message = new Message();
        }
        
        public Builder setOrigin(String origin) {
            message.setOrigin(origin);
            return this;
        }
        
        public Builder setDateReceived(Date dateReceived) {
            message.setDateReceived(dateReceived);
            return this;
        }
        
        public Builder setTitle(String title) {
            message.setTitle(title);
            return this;
        }
        
        public Builder setMessageText(String messageText) {
            message.setMessageText(messageText);
            return this;
        }
        
        public Builder setRead(boolean isRead) {
            message.setRead(isRead);
            return this;
        }
        
        public Message build() {
            return message;
        }
    }
}
